package com.gitee.wsl.mathematics.algebraic.sample

import com.gitee.wsl.mathematics.algebraic.op.Norm
import com.gitee.wsl.mathematics.algebraic.op.PowerOperations
import com.gitee.wsl.mathematics.algebraic.op.isInteger
import com.gitee.wsl.mathematics.algebraic.ExtendedField
import com.gitee.wsl.mathematics.algebraic.number.ScaleOperations
import kotlin.math.abs
import kotlin.math.pow as kpow

interface Float64ExtendedField: ExtendedField<Double>, Norm<Double, Double>, ScaleOperations<Double>

/**
 * A field for [Double] without boxing. Does not produce an appropriate field element.
 */
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
object Float64Field :Float64ExtendedField {

    override val zero: Double get() = 0.0
    override val one: Double get() = 1.0

    override fun number(value: Number): Double = value.toDouble()

    override fun binaryOperationFunction(operation: String): (left: Double, right: Double) -> Double =
        when (operation) {
            PowerOperations.POW_OPERATION -> { l, r -> l.kpow(r) }
            else -> super.binaryOperationFunction(operation)
        }

    override fun add(left: Double, right: Double): Double = left + right

    override fun multiply(left: Double, right: Double): Double = left * right
    override fun divide(left: Double, right: Double): Double = left / right

    override fun scale(a: Double, value: Double): Double = a * value

    override fun sin(arg: Double): Double = kotlin.math.sin(arg)
    override fun cos(arg: Double): Double = kotlin.math.cos(arg)
    override fun tan(arg: Double): Double = kotlin.math.tan(arg)
    override fun acos(arg: Double): Double = kotlin.math.acos(arg)
    override fun asin(arg: Double): Double = kotlin.math.asin(arg)
    override fun atan(arg: Double): Double = kotlin.math.atan(arg)

    override fun sinh(arg: Double): Double = kotlin.math.sinh(arg)
    override fun cosh(arg: Double): Double = kotlin.math.cosh(arg)
    override fun tanh(arg: Double): Double = kotlin.math.tanh(arg)
    override fun asinh(arg: Double): Double = kotlin.math.asinh(arg)
    override fun acosh(arg: Double): Double = kotlin.math.acosh(arg)
    override fun atanh(arg: Double): Double = kotlin.math.atanh(arg)

    override fun sqrt(arg: Double): Double = kotlin.math.sqrt(arg)
    override fun power(arg: Double, pow: Number): Double = when {
        pow.isInteger() -> arg.kpow(pow.toInt())
        arg < 0 -> throw IllegalArgumentException("Can't raise negative $arg to a fractional power $pow")
        else -> arg.kpow(pow.toDouble())
    }

    override fun exp(arg: Double): Double = kotlin.math.exp(arg)
    override fun ln(arg: Double): Double = kotlin.math.ln(arg)

    override fun norm(arg: Double): Double = abs(arg)

    override fun Double.unaryMinus(): Double = -this
    override fun Double.plus(arg: Double): Double = this + arg
    override fun Double.minus(arg: Double): Double = this - arg
    override fun Double.times(arg: Double): Double = this * arg
    override fun Double.div(arg: Double): Double = this / arg
}

 typealias DoubleField = Float64Field

 val Double.Companion.algebra: Float64Field get() = Float64Field